package com.snts.synchronization.protocol.adapter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.naming.OperationNotSupportedException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;

import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Serializer;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.snts.synchronization.core.AuthRequest;
import com.snts.synchronization.core.ErrorObject;
import com.snts.synchronization.garbage.Utils;
import com.snts.synchronization.protocol.ProtocolAdapter;
import com.snts.synchronization.protocol.ProtocolException;

public abstract class BaseXMLProtocolAdapter<T extends Object> extends StringBufferDefaultHandler implements ProtocolAdapter<T> {

	protected ErrorObject errorObject;
	private static final Log log = LogFactory.getLog(BaseXMLProtocolAdapter.class);

	@Override
	public T parseMessage(InputStream is) throws Exception {
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream(4 * 1024);
			IOUtils.copy(is, baos);
			log.debug(new String(baos.toByteArray()));
			SAXParser saxParser = Utils.getSAXParser();
			saxParser.parse(new ByteArrayInputStream(baos.toByteArray()), this);
			return popMessage();
		} catch (Exception e) {
			// TODO LOG4J here
			e.printStackTrace();
			throw new Exception("Excetion during parse of XMLMessage", e);
		}
	}

	protected abstract T popMessage();

	@Override
	public void serializeMessage(T message, OutputStream outputStream) throws UnsupportedOperationException, IOException {
		Document document = new Document(getMessageXOM(message));
		Serializer serializer = new Serializer(outputStream);
		serializer.write(document);
	}

	protected abstract Element getMessageXOM(T message);

	protected void appendTextElement(Element element, String name, String value) {
		Element child = new Element(name);
		child.appendChild(value);
		element.appendChild(child);
	}
	
	protected Element getErrorXOM(ErrorObject errorObject){
		Element error = new Element("error");
		appendTextElement(error, "error-code", "" + errorObject.getErrorCode());
		appendTextElement(error, "error-message", "" + errorObject.getErrorMessage());
		appendTextElement(error, "additional-info", "" + errorObject.getAdditionalInformation());
		return error;
	}

	@Override
	protected void doEndElement(String uri, String localName, String qName, String textValue) throws SAXException {
		if ("error-code".equals(qName)) {
			errorObject.setErrorCode(Integer.parseInt(textValue));
		} else if ("error-message".equals(qName)) {
			errorObject.setErrorMessage(textValue.trim());
		} else if ("additional-info".equals(qName)) {
			errorObject.setAdditionalInformation(textValue.trim());
		}
	}

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if ("error".equals(qName)) {
			errorObject = new ErrorObject();
		}
		super.startElement(uri, localName, qName, attributes);
	}
	
	

}
